//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <mantle.h>
#include <crust.h>
#include "stubio.h"
#include "udbs.h"
#include <string.h>
#include "_sprintf.h"

#ifdef _neptune
#include <nu_api.h>
#endif

#if defined(_UDBAGENT)

//const int_t c_nUdbStubStackSize = 1096;
//
//int_t g_udbStubStack[c_nUdbStubStackSize / sizeof(int_t)];
//
//int_t *g_pUdbStubStack = &g_udbStubStack[c_nUdbStubStackSize / sizeof(int_t) - 1];

#define UDBDBG 0

extern char g_outBuf[c_uBufSize + 32];
extern char g_inBuf[c_uBufSize + 32];

extern int_t g_nMemError;
extern void (*volatile g_pMemFaultRoutine) (void);

extern bool_t g_bDetchedInLastContinueOrNextCmd;
extern UInt32 g_uDetchedAddrInLastContinueOrNextCmd;

extern bool_t g_bLastContinue;

extern Boolean g_bDbgStubEntry;

extern InterruptContext *g_pCurrentCxt;

DLinkNode g_udbBreakpointList;
static int g_udbLastModuleNum = 0;

void UnicToAnsi(char *pszName, const wchar_t *pwszName);

EXTERN_C int CDECL sprintf(char *buf, const char *fmt, ...);
EXTERN_C Boolean CloneMemBlockForProcess(UInt32 uAddr, UInt32 uSize);

typedef struct SymbolInfoBlock : public DLinkNode {
      bool bDate;
      //Every minimal symbol info block is limited to c_uSymInfoBlockSize chars.
      char *pSymInfo;
} SymbolInfoBlock, *PSymbolInfoBlock;

DLinkNode g_udbSymInfoBlockList;
static char *c_pSymBlockPrefix = "qSy:";
static size_t c_uSymInfoBlockSize = c_uBufSize - 40;
static void AllocSymInfoBlock(PSymbolInfoBlock *ppsib);
static void FreeSymInfoBlock(PSymbolInfoBlock psib);
static void FreeAllSymInfoBlock();
static bool UdbIsInSymInfoBlock(char *pModuleName);
static int  UdbGetPresentModuleCount();
static bool_t UdbGetPresentMinSymbolInfo();
static void UdbEnableSymbolInfo();

static wchar_t *UdbGetModuleAbsoluteName(wchar_t *pwszModuleName);

static void UdbQuerySymbols(Boolean bMain);

static void UdbTraceDebugCommandHandle(InterruptContext *pCxt, StubContext *pUdbCxt);

static void UdbReadMem();
static void UdbWriteMem();

static void UdbWriteOneRegister(InterruptContext *pCxt, StubContext *pUdbCxt);
static void UdbWriteRegisters(InterruptContext *pCxt, StubContext *pUdbCxt);

//static char* UdbDirectMemToHexStr(const byte_t *pMem, char *pszBuf, int_t nCount);

static bool_t UdbIsValidAddress(const UInt32 uAddr);

static void UdbInfoQuery(StubContext *pUdbCxt);

static void UdbDetachBreakPoint(InterruptContext *pCxt, StubContext *pUdbCxt);
static void UdbAddBreakPoint(Breakpoint *pHeadBreapoint);
#ifdef _x86
static void UdbDetachBreakBeforTrace(Breakpoint *pHeadBreapoint, UInt32 uEip);
#endif
static bool_t UdbDeleteAllBreakpoint();

static bool_t UdbDumpBreakpointIntoList(Breakpoint *pHeadBreakpoint, UInt32 uAddr);

static void UdbLoop(vector_t vector, InterruptContext *pCxt);
static char *g_pszMainName = NULL;
static UInt32 UdbGetMainModuleRelocOffset();
CProcess *g_pCurrentProcess = NULL;


#ifdef _arm
static UInt32 g_insbp = 0;
static UInt32 *g_addrbp = 0;

static Boolean IsInProxyCodeBound(UInt32 *addr);
static Boolean IsInProxyCodeBound(UInt32 *addr)
{
    if (((UInt32)addr >= PROXY_ENTRY_BASE) &&
        ((UInt32)addr <= (PROXY_ENTRY_BASE + PROXY_ENTRY_SIZE * PROXY_ENTRY_NUM))) {
        return TRUE;
    }
    return FALSE;
}

#endif


static void AllocSymInfoBlock(PSymbolInfoBlock *ppsib)
{
    *ppsib = new SymbolInfoBlock;
    assert(*ppsib != NULL);
    (*ppsib)->bDate = false;
    (*ppsib)->pSymInfo = new char[c_uSymInfoBlockSize];
    assert((*ppsib)->pSymInfo != NULL);
    memset((*ppsib)->pSymInfo, '\0', sizeof(char) * (c_uSymInfoBlockSize));
    strcat((*ppsib)->pSymInfo, c_pSymBlockPrefix);
}

static void FreeSymInfoBlock(PSymbolInfoBlock psib)
{
    assert(psib != NULL);
    assert(psib->pSymInfo != NULL);
    delete psib->pSymInfo;
    delete psib;
}

static void FreeAllSymInfoBlock()
{
    PSymbolInfoBlock p = NULL, ptmp = NULL;

    p = (PSymbolInfoBlock)g_udbSymInfoBlockList.Next();
    while (p != (PSymbolInfoBlock)&g_udbSymInfoBlockList) {
        ptmp = (PSymbolInfoBlock)p->Next();
        p->Detach();
        FreeSymInfoBlock(p);
        p = ptmp;
    }
    g_udbSymInfoBlockList.Initialize();
}

static int  UdbGetPresentModuleCount()
{
    assert(g_pCurrentProcess);

    int nCount = 0;
    ModuleView  *pModuleView = (ModuleView *)(g_pCurrentProcess->m_moduleList.Next());

    while (pModuleView != &(g_pCurrentProcess->m_moduleList)) {
        nCount++;
        pModuleView = (ModuleView *)(pModuleView->Next());
    }

    return nCount;
}

static UInt32 UdbGetMainModuleRelocOffset()
{
    assert(g_pCurrentProcess);
    char tmp[256] = {'\0'};

    ModuleView  *pModuleView = (ModuleView *)(g_pCurrentProcess->m_moduleList.Next());
    while (pModuleView != &(g_pCurrentProcess->m_moduleList)) {
        memset(tmp, '\0', 256 * sizeof(char));
        UnicToAnsi(tmp, UdbGetModuleAbsoluteName(pModuleView->m_pModule->m_wszName));
        int tmlen = strlen(tmp);
        tmlen--;
        if (((tmp[tmlen] == 'e') && (tmp[tmlen - 1] == 'x') && (tmp[tmlen - 2] == 'e')
            && (tmp[tmlen - 3] == '.')) || ((tmp[tmlen] == 'E') && (tmp[tmlen - 1] == 'X')
            && (tmp[tmlen - 2] == 'E') && (tmp[tmlen - 3] == '.'))) {
            return pModuleView->m_pModule->m_uRelocOffset;
        }
        pModuleView = (ModuleView *)(pModuleView->Next());
    }

    return 0xFFFFFFFF;
}

static bool UdbIsInSymInfoBlock(char *pModuleName)
{
    PSymbolInfoBlock p = NULL;

    p = (PSymbolInfoBlock)g_udbSymInfoBlockList.Next();
    while (p != (PSymbolInfoBlock)&g_udbSymInfoBlockList) {
        if (NULL != strstr(p->pSymInfo, pModuleName)) {
            return true;
        }
        p = (PSymbolInfoBlock)p->Next();
    }
    return false;
}

static void UdbEnableSymbolInfo()
{
    PSymbolInfoBlock psib = (PSymbolInfoBlock)g_udbSymInfoBlockList.Next();
    while (psib != (PSymbolInfoBlock)&g_udbSymInfoBlockList) {
        psib->bDate = false;
        psib = (PSymbolInfoBlock)psib->Next();
    }
}

static void UdbQuerySymbols(Boolean bMain)
{
    g_outBuf[0] = '\0';

    if (bMain) {
        if (g_pszMainName == NULL) {
            kprintf("\nCan't find modules\n");
            return;
        }
        strcpy(g_outBuf, g_pszMainName);
        return;
    }

    assert(!g_udbSymInfoBlockList.IsEmpty());

    PSymbolInfoBlock psib = (PSymbolInfoBlock)g_udbSymInfoBlockList.Next();
    while (psib != (PSymbolInfoBlock)&g_udbSymInfoBlockList) {
        if (!psib->bDate) {
            strcat(g_outBuf, psib->pSymInfo);
            psib->bDate = true;
            if ((PSymbolInfoBlock)&g_udbSymInfoBlockList == (PSymbolInfoBlock)psib->Next()) {
                //Add finished Suffix 'F' at the last symbol block
                int len = strlen(g_outBuf);
                g_outBuf[len] = 'F';
                g_outBuf[len + 1] = '\0';
            }
            break;
        }

        psib = (PSymbolInfoBlock)psib->Next();
    }

    if (g_outBuf[0] == '\0') {
        strcpy(g_outBuf, "OK");
    }
}

static bool_t UdbGetPresentMinSymbolInfo()
{
    int nCurCount = UdbGetPresentModuleCount();
    if (g_udbLastModuleNum == nCurCount) return TRUE;
    else {
        //BUGBUG: Don't involve the state of dynamicly uninstalling DLL
        g_udbLastModuleNum = nCurCount;
    }

    assert(g_pCurrentProcess);

    ModuleView *pModuleView = NULL;
    const uint_t c_uMaxOneSymInfoSize = 500;
    const int_t c_invalidSectionIndex = -1;
    uint_t is;
    int_t uText = c_invalidSectionIndex;
    int_t uData = c_invalidSectionIndex;
    int_t uBss = c_invalidSectionIndex;

    char oneSymInfo[c_uMaxOneSymInfoSize];
    char *pOneSymInfo = NULL;
    const uint_t c_uTmpSize = 100;
    char tmp[c_uTmpSize];
    wchar_t *pwszModuleAbsName = NULL;

    PSymbolInfoBlock psib = NULL;

    AllocSymInfoBlock(&psib);
    g_udbSymInfoBlockList.InsertLast(psib);

    char *pCurSymInfo = psib->pSymInfo;

    pModuleView = (ModuleView *)(g_pCurrentProcess->m_moduleList.Next());

    //
    //format:FILE ADDR [-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> ...];
    //
    while (pModuleView != &(g_pCurrentProcess->m_moduleList)) {
        memset(oneSymInfo, '\0', c_uMaxOneSymInfoSize * sizeof(char));
        pOneSymInfo = oneSymInfo;

        //Get symbol name
        memset(tmp, '\0', c_uTmpSize * sizeof(char));
        pwszModuleAbsName = UdbGetModuleAbsoluteName(pModuleView->m_pModule->m_wszName);
        assert(pwszModuleAbsName);
        UnicToAnsi(tmp, pwszModuleAbsName);
        if (UdbIsInSymInfoBlock(tmp)) {
            pModuleView = (ModuleView *)(pModuleView->Next());
            continue;
        }

        //// Save the main name
        int tmlen = strlen(tmp);
        tmlen--;
        if (((tmp[tmlen] == 'e') && (tmp[tmlen - 1] == 'x') && (tmp[tmlen - 2] == 'e')
            && (tmp[tmlen - 3] == '.')) || ((tmp[tmlen] == 'E') && (tmp[tmlen - 1] == 'X')
            && (tmp[tmlen - 2] == 'E') && (tmp[tmlen - 3] == '.'))) {
            g_pszMainName = new char[strlen(tmp) + 1];
            assert(g_pszMainName);
            strcpy(g_pszMainName, tmp);
        }

        *pOneSymInfo = '\0';
        strcat(pOneSymInfo, tmp);
        pOneSymInfo += strlen(tmp);

        //Get some section indexes
        for (is = 0; is < pModuleView->m_pModule->m_cSections; is++) {
            if (!strcmp(pModuleView->m_pModule->m_pSections[is].m_szName, \
                ".text")) {
                uText = is;
            }

            if (!strcmp(pModuleView->m_pModule->m_pSections[is].m_szName, \
                ".data")) {
                uData = is;
            }

            if (!strcmp(pModuleView->m_pModule->m_pSections[is].m_szName, \
                ".bss")) {
                uBss = is;
            }
        }

        // Get the address of the .text
        memset(tmp, '\0', c_uTmpSize * sizeof(char));
        strcat(pOneSymInfo, " 0x");
        pOneSymInfo += 3;
        sprintf(tmp, "%x", pModuleView->m_pModule->m_uImageBase + \
                pModuleView->m_pModule->m_pSections[uText].m_uVAddr);
        strcat(pOneSymInfo, tmp);
        pOneSymInfo += strlen(tmp);

        // Get the address of the .data
        if (c_invalidSectionIndex != uData) {
            memset(tmp, '\0', c_uTmpSize * sizeof(char));
            strcat(pOneSymInfo, " -s .data 0x");
            pOneSymInfo += 12;
            sprintf(tmp, "%x", pModuleView->m_pModule->m_uImageBase + \
                    pModuleView->m_pModule->m_pSections[uData].m_uVAddr);
            strcat(pOneSymInfo, tmp);
            pOneSymInfo += strlen(tmp);
        }

        // Get the address of the .bss
        if (c_invalidSectionIndex != uBss) {
            memset(tmp, '\0', c_uTmpSize * sizeof(char));
            strcat(pOneSymInfo, " -s .bss 0x");
            pOneSymInfo += 11;
            sprintf(tmp, "%x", pModuleView->m_pModule->m_uImageBase + \
                    pModuleView->m_pModule->m_pSections[uBss].m_uVAddr);
            strcat(pOneSymInfo, tmp);
            pOneSymInfo += strlen(tmp);
        }

        // Suffix ';'
        *pOneSymInfo++ = ';';

        // Add one symbol info into the current symbol block
        uint_t uCurFree = c_uSymInfoBlockSize - strlen(pCurSymInfo) - 2;
        if (uCurFree >= (strlen(oneSymInfo) + 2)) {
            strcat(pCurSymInfo, oneSymInfo);
        }
        else {//alloca a new symbol block
            AllocSymInfoBlock(&psib);
            g_udbSymInfoBlockList.InsertLast(psib);
            pCurSymInfo = psib->pSymInfo;
            strcat(pCurSymInfo, oneSymInfo);
        }

        pModuleView = (ModuleView *)(pModuleView->Next());
    }

    return TRUE;
}

static bool_t UdbIsValidAddress(const UInt32 uAddr)
{
    assert(g_pCurrentProcess);

    if (g_pCurrentProcess->m_AS.IsValidAddress(uAddr)) {
        return TRUE;
    }

    return FALSE;
}


#if 0
static char* UdbDirectMemToHexStr(const byte_t *pMem, char *pszBuf, int_t nCount)
{
    int_t i;
    uchar_t uch;


    pMem += nCount - 1;


    for (i = 0; i < nCount; i++, pMem--) {
        uch = *(byte_t *)pMem;
        if (g_nMemError) {
            g_pMemFaultRoutine = NULL;
            return NULL;
        }

        *pszBuf++ = c_arrHexChars[uch >> 4];
        *pszBuf++ = c_arrHexChars[uch & 0x0f];
    }


    *pszBuf = '\0';
    g_pMemFaultRoutine = NULL;


    return pszBuf;
}
#endif


static void UdbWriteRegisters(InterruptContext *pCxt, StubContext *pUdbCxt)
{
    uint_t uLen, nCount;

    g_outBuf[0] = '\0';


    uLen = strlen(&g_inBuf[1]);
    if (uLen > c_uRegBytes * 2) {
        uLen = c_uRegAllBytes * 2;
    }


    nCount = uLen / 2;


    if(!HexStrToMem(&g_inBuf[1], (byte_t *)pUdbCxt, nCount)) {
        memcpy(g_outBuf, "E01", 3);
        g_outBuf[3] = '\0';
        return;
    }

    GDB_FLUSH_CACHE

    memcpy(g_outBuf, "OK", 2);
    g_outBuf[2] = '\0';


    pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
}



static void UdbWriteOneRegister(InterruptContext *pCxt, StubContext *pUdbCxt)
{
    int_t nReg, nCount;
    byte_t arrBytes[c_uRegAllBytes];
    const char *ptr = NULL;

    g_outBuf[0] = '\0';


    ptr = ParseRegCommand(g_inBuf, &nReg, arrBytes, &nCount);
    if (ptr == NULL) {
        memcpy (g_outBuf, "E01", 3);
        g_outBuf[3] = '\0';
        return;
    }


    memcpy((ulong_t *)((uint8_t *)pUdbCxt + nReg * 4), arrBytes, nCount);
    memcpy(g_outBuf, "OK", 2);
    g_outBuf[2] = '\0';


    pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
}



static void UdbWriteMem()
{
    //
    // Write memory in the case of the single thread
    //

    byte_t *pAddr;
    int_t nCount;
    const char *ptr = NULL;

    g_outBuf[0] = '\0';

    ptr = ParseMemCommand(g_inBuf, &pAddr, &nCount);
    if (ptr == NULL) {
        memcpy(g_outBuf, "E01", 4);
        return;
    }


    if (!UdbIsValidAddress((UInt32)pAddr)) return;


    //Write ptr to the addr
    if (nCount >= (int_t)(AlignPageUp((UInt32)pAddr) - (UInt32)pAddr)) {
        nCount = (int_t)(AlignPageUp((UInt32)pAddr) - (UInt32)pAddr);
    }

    if (!HexStrToMem(ptr, pAddr, nCount)) {
        memcpy(g_outBuf, "E03", 4);
        return;
    }

    GDB_FLUSH_CACHE

    memcpy(g_outBuf, "OK", 3);
}



static void UdbReadMem()
{
    //
    // Read memory in the case of the single thread
    //

    byte_t *pAddr;
    int_t nCount;
    const char *ptr = NULL;

    g_outBuf[0] = '\0';

    ptr = ParseMemCommand(g_inBuf, &pAddr, &nCount);

    if (ptr == NULL) {
        memcpy(g_outBuf, "E01", 4);
        return;
    }


    if (!UdbIsValidAddress((UInt32)pAddr)) return;


    if (nCount > ((int_t)c_uBufSize / 2)) {
        nCount = (int_t)c_uBufSize / 2;
    }

    if (nCount >= (int_t)(AlignPageUp((UInt32)pAddr + 1) - (UInt32)pAddr)) {
        nCount = (int_t)(AlignPageUp((UInt32)pAddr + 1) - (UInt32)pAddr);
    }

    // read the content of the memory address 'addr'
    if (MemToHexStr(pAddr, g_outBuf, nCount) == NULL) {
        memcpy(g_outBuf, "E03", 4);
        return;
    }
}

static void UdbTraceDebugCommandHandle(InterruptContext *pCxt, StubContext *pUdbCxt)
{
#ifdef _x86
    int_t nAddr;
    const char *ptr = NULL;

    UdbDetachBreakBeforTrace((Breakpoint *)&g_udbBreakpointList, pUdbCxt->eip);

    ptr = &g_inBuf[1];
    if (HexWordStrToInt(ptr, &nAddr) != NULL) {
        pUdbCxt->SetEip(nAddr);
    }

    if (g_inBuf[0] == 's') {
        pUdbCxt->EnableTrace();
    }
    else {
        if (g_bLastContinue) {
            pUdbCxt->EnableTrace();
        }else {
            pUdbCxt->DisableTrace();
        }
    }

    pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
#endif

#ifdef _arm
    //pc point the instruction should be interrupt, and next time to be execute again
    g_cpArmCurrentCxt = pUdbCxt;
    Boolean ret;
    if (g_inBuf[0] == 's') {
        /*
         * we stopped, and is not caused by a 'step(i)' or 'next(i)', just save the original instruction
         */
        if (g_addrbp == 0) {
            g_addrbp = (UInt32 *)arm_target_ins((UInt32 *)pUdbCxt->pc, *(UInt32 *)pUdbCxt->pc);
            pUdbCxt->pc = (UInt32)g_addrbp;
        }
        else {
            /*
             * we stopped by a 'step(i)' or 'next(i)', we should restore the original instruction 
             * and set a new breakpoint in the next instruction.
             */
            *g_addrbp = g_insbp;
            UInt32 *addrnext = arm_target_ins(g_addrbp, (UInt32)*g_addrbp);
            pUdbCxt->pc = (UInt32)g_addrbp;
            g_addrbp = addrnext;
        }

        while(IsInProxyCodeBound(g_addrbp)) {
            UInt32 ins = *g_addrbp;
            g_addrbp = arm_target_ins(g_addrbp, ins);
        }

        ret = CloneMemBlockForProcess((UInt32)g_addrbp, BREAK_INSTRUCTION_LENGTH);
        if (!ret)
            return;

        if (*g_addrbp == BREAK_INSTRUCTION) {
            /*
             * if next step we will step into a breakpoint, just continue to it!
             * or we will stay in the breakpoint twice: first time for the breakpoint 
             * which is set by 'step', second for the original breakpoint.
             */
            g_addrbp = 0;
        }
        else {
            g_insbp = *g_addrbp;
            *g_addrbp = BREAK_INSTRUCTION;
        }

        GDB_FLUSH_CACHE
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
        return;
    }

    if (g_inBuf[0] == 'c') {
        //skip hard-coded breakpoint
        if (*(UInt32 *)pUdbCxt->pc == BREAK_INSTRUCTION) {
            pUdbCxt->pc += 4;
            GDB_FLUSH_CACHE
            pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
        }

        if (g_addrbp == 0) return;
        *g_addrbp = g_insbp;
        pUdbCxt->pc = (UInt32)g_addrbp;

        GDB_FLUSH_CACHE
        g_addrbp = 0;
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
        return;
    }
#endif
}


#if 0
static bool_t UdbFindModuleName(const UInt32 uEip)
{
    ModuleView *pModuleView = NULL;

    assert(g_pCurrentProcess);

    ForEachDLinkNode(ModuleView *, pModuleView, \
                    &(g_pCurrentProcess->m_moduleList)) {
        if ((uEip >= pModuleView->m_pModule->m_uImageBase) \
            && (uEip <= (pModuleView->m_pModule->m_uImageBase \
                + pModuleView->m_pModule->m_uTotalSize))) {
            break;
        }
    }

    if (pModuleView == (ModuleView *)&(g_pCurrentProcess->m_moduleList)) {
        kprintf("Module not found at the address 0x%08x\n", uEip);
        strcpy(g_outBuf, "E02");
        return FALSE;
    }

    UnicToAnsi(g_outBuf, UdbGetModuleAbsoluteName(pModuleView->m_pModule->m_wszName));
    g_outBuf[strlen(g_outBuf)] = '\0';

    return TRUE;
}
#endif

static wchar_t *UdbGetModuleAbsoluteName(wchar_t *pwszModuleName)
{
    assert(pwszModuleName);
    wchar_t *pwszAbsoluteName = pwszModuleName + wcslen(pwszModuleName) - 1;

    while (pwszAbsoluteName > pwszModuleName) {
        if (*pwszAbsoluteName == L'\\' || *pwszAbsoluteName == L'/') {
            break;
        }
        pwszAbsoluteName--;
    }

    if (*pwszAbsoluteName == L'\\' || *pwszAbsoluteName == L'/') {
        pwszAbsoluteName++;
    }
    return pwszAbsoluteName;
}


static void UdbInfoQuery(StubContext *pUdbCxt)
{
    g_outBuf[0] = '\0';


    // qC
    if (g_inBuf[1] == 'C') {
        strcat(g_outBuf, "OK");
        return;
    }


    // qOffsets
    if (!strcmp(g_inBuf, "qOffsets")) {
        char szOff[20] = {'\0'};
        UInt32 offset = UdbGetMainModuleRelocOffset();
        MemToHexStr((byte_t *)&offset, szOff, sizeof(UInt32));
        strcat(g_outBuf, "Text=");
        strcat(g_outBuf, szOff);
        strcat(g_outBuf, ";");
        strcat(g_outBuf, "Data=");
        strcat(g_outBuf, szOff);
        strcat(g_outBuf, ";");
        strcat(g_outBuf, "Bss=");
        strcat(g_outBuf, szOff);
        g_outBuf[strlen(g_outBuf)] =  '\0';
        return;
    }

    //qSymbol::
    if (!strcmp(g_inBuf, "qSymbol::")) {
        strcat(g_outBuf, "OK");
        return;
    }

    if (!strcmp(g_inBuf, "qSM::")) {
        UdbQuerySymbols(TRUE);
        UdbEnableSymbolInfo();
        return;
    }

    // qSy defined by us on 2004-3-4,
    // used in the remote communication when dynamically loading dlls
    if (!strcmp(g_inBuf, "qSy::")) {
        UdbQuerySymbols(FALSE);
        return;
    }
}


static void UdbDetachBreakPoint(InterruptContext *pCxt, StubContext *pUdbCxt)
{
    int_t nRet, nType, nLen;
    byte_t  *pAddr;
    Breakpoint *pTemp, *pNext;


    if (g_inBuf[1] == 'z') {
        nRet = 1;

#ifdef _x86
        pUdbCxt->SetEip(pUdbCxt->eip - c_uDbgInstructionLen);
#endif
#ifdef _arm
        pUdbCxt->pc = pUdbCxt->pc - BREAK_INSTRUCTION_LENGTH;
#endif
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);

        pNext = (Breakpoint *)(g_udbBreakpointList.Next());
        while (pNext != (Breakpoint *)&g_udbBreakpointList) {
            if (!HexStrToMem(pNext->buf, pNext->pAddr, BREAK_INSTRUCTION_LENGTH)) {
                nRet = 0;
            }

            pNext->Detach();
            delete pNext;
            pNext = (Breakpoint *)(g_udbBreakpointList.Next());
        }

        if (nRet) {
            memcpy(g_outBuf, "OK", 3);
        }
        else {
            memcpy(g_outBuf, "E04", 4);
        }
        return;
    }


    nRet = ParseBreakpointCommand(g_inBuf, &nType, &pAddr, &nLen);

    if (!nRet) {
        memcpy(g_outBuf, "E01", 4);
        return;
    }

    if (nType != 0) return;

    if (nLen != BREAK_INSTRUCTION_LENGTH) {
        memcpy(g_outBuf, "E02", 4);
        return;
    }

    ForEachDLinkNode(Breakpoint *, pTemp, &g_udbBreakpointList) {
        if(pTemp->pAddr == pAddr) {
           break;
        }
    }

    if (pTemp == (Breakpoint *)&g_udbBreakpointList) {
        memcpy(g_outBuf, "E03", 4);
        return;
    }

    if (!HexStrToMem(pTemp->buf, pTemp->pAddr, BREAK_INSTRUCTION_LENGTH)) {
        memcpy(g_outBuf, "E04", 4);
        return;
    }

    GDB_FLUSH_CACHE

    pTemp->Detach();
    delete pTemp;


    memcpy(g_outBuf, "Ok", 3);

#ifdef _x86
    if ((pUdbCxt->eip - c_uDbgInstructionLen) == (UInt32)pAddr) {
        pUdbCxt->SetEip(pUdbCxt->eip - c_uDbgInstructionLen);
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
    }
#endif
#ifdef _arm
    if ((pUdbCxt->pc - BREAK_INSTRUCTION_LENGTH) == (UInt32)pAddr) {
        pUdbCxt->pc = (UInt32)pAddr;
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
    }
#endif
}



static void UdbAddBreakPoint(Breakpoint *pHeadBreapoint)
{
    int_t nRet, nType, nLen;
    byte_t *pAddr;


    nRet = ParseBreakpointCommand(g_inBuf, &nType, &pAddr, &nLen);

    if (!nRet) {
        memcpy(g_outBuf, "E01", 4);
        return;
    }

    if (nType != 0) return;

    if (nLen != BREAK_INSTRUCTION_LENGTH) {
        memcpy(g_outBuf, "E02", 4);
        return;
    }

    if (UdbDumpBreakpointIntoList(pHeadBreapoint, (UInt32)pAddr)) {
        memcpy(g_outBuf, "OK", 3);
    }
    else {
        memcpy(g_outBuf, "E03", 4);
    }
}


#ifdef _x86
static void UdbDetachBreakBeforTrace(Breakpoint *pHeadBreapoint, UInt32 uEip)
{
    Breakpoint *pTemp;

    ForEachDLinkNode(Breakpoint *, pTemp, pHeadBreapoint) {
        if(pTemp->pAddr == (byte_t *)uEip) {
           break;
        }
    }

    if (pTemp != pHeadBreapoint) {
        if (!HexStrToMem(pTemp->buf, pTemp->pAddr, BREAK_INSTRUCTION_LENGTH)) {
            memcpy(g_outBuf, "E01", 4);
            return ;
        }

        GDB_FLUSH_CACHE

        pTemp->Detach();
        delete pTemp;

        g_bDetchedInLastContinueOrNextCmd = TRUE;

        g_uDetchedAddrInLastContinueOrNextCmd = uEip;
    }

}
#endif


static bool_t UdbDumpBreakpointIntoList(Breakpoint *pHeadBreakpoint, UInt32 uAddr)
{
    Breakpoint *pBreakpoint;


    if (uAddr == 0) {
        return FALSE;
    }


    // find the breakpoint ip
    ForEachDLinkNode(Breakpoint *, pBreakpoint, pHeadBreakpoint) {
        if (pBreakpoint->pAddr == (byte_t *)uAddr) {
            return TRUE;
        }
    }


    pBreakpoint = new(Breakpoint);
    if (pBreakpoint == NULL) return FALSE;

#ifdef _arm
    if ((UInt32)g_addrbp == uAddr) {
        *g_addrbp = g_insbp;
    }
#endif
    // save the content of address and write breakpoint instruction
    // into the address, "cc" is the machine instruction of the
    // instruction "int $3"
    if (MemToHexStr((byte_t *)uAddr, pBreakpoint->buf, BREAK_INSTRUCTION_LENGTH) == NULL \
        || !HexStrToMem(BREAK_INSSTRING, (byte_t *)uAddr, BREAK_INSTRUCTION_LENGTH)) {
        delete pBreakpoint;
        return FALSE;
    }

    GDB_FLUSH_CACHE

    pBreakpoint->pAddr = (byte_t *)uAddr;
    pHeadBreakpoint->InsertFirst(pBreakpoint);

    return TRUE;
}



static bool_t UdbDeleteAllBreakpoint()
{
    Breakpoint *pTemp, *pNext;


    if (g_udbBreakpointList.IsEmpty()) return TRUE;


    pTemp = (Breakpoint *)(g_udbBreakpointList.Next());
    while (pTemp != (Breakpoint *)&g_udbBreakpointList) {
        if (!HexStrToMem(pTemp->buf, pTemp->pAddr, BREAK_INSTRUCTION_LENGTH)) {
            return FALSE;
        }

        pNext = (Breakpoint *)pTemp->Next();
        pTemp->Detach();
        delete pTemp;

        pTemp = pNext;
    }
    return TRUE;
}


//The gdb command processor.
static void UdbLoop(vector_t vector, InterruptContext *pCxt)
{
    StubContext udbCxt;
    g_pCurrentCxt = pCxt;
    StubContext *pUdbCxt = &udbCxt;
    pUdbCxt->SetupUdbContext(pCxt, pUdbCxt);

    CProcess *pCurrentProcess = GetCurrentProcess();
    assert(pCurrentProcess);

    if (g_pCurrentProcess && (g_pCurrentProcess != pCurrentProcess)) {
        WStringBuf_<64> esbName, esbArgs;
        pCurrentProcess->GetStartInfo(&esbName, &esbArgs);
        kprintf("\n[Modules:] %S %S : %d\n", (wchar_t *)esbName.GetPayload(), (wchar_t *)esbArgs.GetPayload(), vector);
        kprintf("WARNING: Another process has been broke down because of the step command!\n");
        return;
    }


#ifdef _arm
    if (g_addrbp) {
        if (IsInProxyCodeBound(g_addrbp)) {
            UInt32 *addrnext = arm_target_ins(g_addrbp, (UInt32)*g_addrbp);
            pUdbCxt->pc = (UInt32)g_addrbp;
            g_addrbp = addrnext;

            while(IsInProxyCodeBound(g_addrbp)) {
                UInt32 ins = *g_addrbp;
                g_addrbp = arm_target_ins(g_addrbp, ins);
            }

            _ELASTOS Boolean ret = CloneMemBlockForProcess((UInt32)g_addrbp, BREAK_INSTRUCTION_LENGTH);
            if(!ret)  return;

            g_insbp = *g_addrbp;
            *g_addrbp = BREAK_INSTRUCTION;
            GDB_FLUSH_CACHE
            pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
            return;
        }
    }
#endif

    if (!g_bDbgStubEntry) {
        g_pCurrentProcess = GetCurrentProcess();
        assert(g_pCurrentProcess);
        FreeAllSymInfoBlock();
        g_udbLastModuleNum = 0;
        g_bDbgStubEntry = TRUE;
    }

    UdbGetPresentMinSymbolInfo();

#ifdef _x86
    if (g_bDetchedInLastContinueOrNextCmd) {

        UdbDumpBreakpointIntoList((Breakpoint *)&g_udbBreakpointList, \
                            g_uDetchedAddrInLastContinueOrNextCmd);

        g_bDetchedInLastContinueOrNextCmd = FALSE;
        g_uDetchedAddrInLastContinueOrNextCmd = 0;
    }

    if (g_bLastContinue) {
        pUdbCxt->DisableTrace();
        pUdbCxt->RestoreUdbInterruptContext(pCxt, pUdbCxt);
        g_bLastContinue = FALSE;
        return;
    }
#endif

    GetTargetCurrentState(vector, pUdbCxt);

    AtomicPutDebugPacket(g_outBuf);

    for(;;) {

        g_outBuf[0] = '\0';

        AtomicGetDebugPacket(g_inBuf);

        if (UDBDBG) DebugPrint("\n\n    UdbStub_receive = ", g_inBuf);

        switch (g_inBuf[0]) {

            case '?':
                GetTargetCurrentState(vector, pUdbCxt);
                break;

            case 'g':               // Read All registers
                MemToHexStr((byte_t *)pUdbCxt, g_outBuf, c_uRegAllBytes);
                break;

            case 'q' :              // query
                UdbInfoQuery(pUdbCxt);
                break;

            case 'H' :              // Responds with 'OK' only.
                memcpy(g_outBuf, "OK", 3);
                break;

            case 'X':
                memcpy(g_outBuf, "OK", 3);
                break;

            case 'G':               // write registers.
                UdbWriteRegisters(pCxt, pUdbCxt);
                break;

            case 'p':
            {
//                int regnum;
//                if (1 == strlen(g_inBuf + 1)) {
//                    if (!HexCharToInt(g_inBuf[1], &regnum)) {
//                        memcpy(g_outBuf, "E01", 4);
//                        break;
//                    }
//                }
//                else {
//                    if (!HexStrToByte(g_inBuf + 1, &regnum)) {
//                        memcpy(g_outBuf, "E01", 4);
//                        break;
//                    }
//                }
//                byte_t *boff = (byte_t *)((uint_t *)pUdbCxt + regnum);
//                MemToHexStr(boff, g_outBuf, c_uRegBytes);
                break;
            }
            case 'P':               // write some register
                UdbWriteOneRegister(pCxt, pUdbCxt);
                break;

            case 'm':               // read memory.
                UdbReadMem();
                break;

            case 'M':               //write memory.
                UdbWriteMem();
                break;

            case 'Z':
                UdbAddBreakPoint((Breakpoint *)&g_udbBreakpointList);
                break;

            case 'z':
                UdbDetachBreakPoint(pCxt, pUdbCxt);
                break;

            case 'c':
                g_bLastContinue = TRUE;
            case 's':
            {
#ifdef _x86
                if (!UdbIsValidAddress(pUdbCxt->eip)) {
#endif
#ifdef _arm
                if (!UdbIsValidAddress(pUdbCxt->pc)) {
#endif
                    memcpy(g_outBuf, "E01", 4);
                    break;
                }

                UdbTraceDebugCommandHandle(pCxt, pUdbCxt);

                return;
            }

            case 'k':
            case 'D':
                g_bDbgStubEntry = FALSE;
                FreeAllSymInfoBlock();
                UdbDeleteAllBreakpoint();
                delete g_pszMainName;
                g_pszMainName = NULL;
                if (g_inBuf[0] == 'D') {
                    memcpy(g_outBuf, "OK", 3);
                    AtomicPutDebugPacket(g_outBuf);
                    g_outBuf[0] = '\0';
                }
                assert(g_pCurrentProcess);
                g_pCurrentProcess->Kill();
                g_pCurrentProcess = NULL;
                break;

            default:
            break;

         }//End switch

         if (UDBDBG) DebugPrint("\n    UdbStub_send = ", g_outBuf);

         AtomicPutDebugPacket(g_outBuf);

    }//End for
}

#endif //#if defined(_UDBAGENT)


void UdbHandler(vector_t vector, InterruptContext *pCxt)
{
#if defined(_UDBAGENT)
    uint32_t uFlags = SaveFlagsAndCli();
#if 0
    SwitchToUdbStack((uint32_t)g_pUdbStubStack);
#endif
    UdbLoop(vector, pCxt);

    RestoreIF(uFlags);
#else
    kputs("App panic (UDB disabled).\n");
#ifdef _neptune
    nu_EnableVibrator(NULL, 1);
    DzDelay(10 * 1000000);
    nu_EnableVibrator(NULL, 0);
#endif
    // TODO:kill user process
    BspHalt();
#endif
}

